package com.class5.springboot.frame.context.bean;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.alibaba.fastjson.JSONObject;
import com.class5.springboot.config.ResultEnum;
import com.class5.springboot.frame.web.result.ResultFailure;
import com.class5.springboot.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.error.ErrorAttributes;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.alibaba.fastjson.JSON;
import org.springframework.web.context.request.ServletWebRequest;

public abstract class SuperErrorController implements ErrorController {
    private static final String ERROR_PATH = "/error";
    @Autowired
    private ErrorAttributes errorAttributes;
    // 是否在调试模式，调试模式下将直接输出验证码
    @Value("${myconfig.security.debugModel}")
    private String debugModel;
//	@Value("${myconfig.web.host}")
//	private String host;

    private boolean isDebugModel() {
        return "true".equals(debugModel);
    }

    @RequestMapping(value = ERROR_PATH)
    public void handleError(HttpServletRequest request, HttpServletResponse response, Exception e) throws IOException {
        // 如果是RestApi执行直接输出
//        if (isRestApiPath(request.getServletPath())) {
//            return "forward:/error_rest_api";
//        }
        Map map  = buildBody(request, true);
        if((map.get("status")+"").equals("400")){
            Map<String, String> rmap = getErrorMessage(request);
            ResultFailure rf = new ResultFailure(null, isDebugModel(), request);
            rf.setErrcode(rmap.get("status"));
            rf.setErrmsg(rmap.get("message"));
            response.setContentType("application/json");
            response.setCharacterEncoding("UTF-8");
            response.getWriter().println(JSON.toJSONString(rf));
        }
        if((map.get("status")+"").equals("404")){
            response.setStatus(404);
            Map<String, String> rmap = getErrorMessage(request);
            ResultFailure rf = new ResultFailure(null, isDebugModel(), request);
            rf.setErrcode(rmap.get("status"));
            rf.setErrmsg(rmap.get("message"));
            response.setContentType("application/json");
            response.setCharacterEncoding("UTF-8");
            response.getWriter().println(JSON.toJSONString(rf));
        }
        if((map.get("status")+"").equals("500")){
            Map<String, String> rmap = getErrorMessage(request);
            ResultFailure rf = new ResultFailure(e, isDebugModel(), request);
            rf.setErrcode(rmap.get("status"));
            if(rmap.get("message").equals(ResultEnum.LOGIN_ERROR_401)||
                    rmap.get("message").equals(ResultEnum.LOGIN_ERROR_TOKENERROR)||
                    rmap.get("message").equals(ResultEnum.LOGIN_ERROR_TOKEN_TIMEOUT)){
                rf.setErrcode("401");
                rf.setErrmsg(rmap.get("message"));
            }if(rmap.get("message").equals(ResultEnum.LOGIN_ERROR_403)){
                rf.setErrcode("403");
                rf.setErrmsg(rmap.get("message"));
            }
            JSONObject debug = rf.getDebug();
            if (debug!=null) {
                debug.put("webexp", rmap.get("trace").replace("\t", "    ").replace("\r","").split("\n"));
            }else{
                if(StringUtils.isNull(rf.getErrmsg())){
                    rf.setErrmsg(rmap.get("message"));
                }
            }
            if(StringUtils.isNull(rf.getErrmsg())){
                rf.setErrmsg("系统错误");
            }
            response.setContentType("application/json");
            response.setCharacterEncoding("UTF-8");
            response.getWriter().println(JSON.toJSONString(rf));
        }
    }

    private Map buildBody(HttpServletRequest request, Boolean includeStackTrace) {
        Map<String, Object> errorAttributes = getErrorAttributes(request, includeStackTrace);
        Integer status = (Integer) errorAttributes.get("status");
        String path = (String) errorAttributes.get("path");
        String messageFound = (String) errorAttributes.get("message");
        String message = "";
        String trace = "";
        if (path != null) {
            message = String.format("Requested path %s with result %s", path, messageFound);
        }
        message += "\r\nstatus:" + status + ",";
        if (includeStackTrace) {
            trace = (String) errorAttributes.get("trace");
            if (trace != null) {
                message += String.format(" and trace %s", trace);
            }
        }
        for (String key : errorAttributes.keySet()) {
            message += key + ":" + errorAttributes.get(key) + ";";
        }
        System.out.println(message);
        errorAttributes.put("message",message);
        return errorAttributes;
    }

    @RequestMapping(value = "/error_rest_api")
    @ResponseBody
    public String handleErrorForRest(HttpServletRequest request) {
        Map<String, Object> attrs = getErrorAttributes(request, false);
        ResultFailure rf = new ResultFailure();
        String msg = (String) attrs.get("message");
        if (msg == null) {
            msg = (String) attrs.get("error");
        }
        Object status = attrs.get("status");
        if (status != null && "404".equals(status)) {
            msg = "请求路径不存在";
        }
        rf.setErrmsg(msg);
        rf.setErrcode(status == null ? "-1" : status.toString());
        return JSON.toJSONString(rf);
    }

    private List<AntPathMatcher> ants = null;

    private boolean isRestApiPath(String path) {
        if (path == null || path.trim().isEmpty())
            return false;
        if (ants == null) {
            ants = new ArrayList<AntPathMatcher>();
            ants.add(new AntPathMatcher("/api/**"));
        }
        for (AntPathMatcher ant : ants) {
            if (ant.isPattern(path)) {
                return true;
            }
        }
        return false;
    }


    @Override
    public String getErrorPath() {
        return ERROR_PATH;
    }

    private Map<String, Object> getErrorAttributes(HttpServletRequest request, boolean includeStackTrace) {
        ServletWebRequest requestAttributes = new ServletWebRequest(request);
        return errorAttributes.getErrorAttributes(requestAttributes, includeStackTrace);
    }


    /*
     * 获取错误信息，返回前端进行处理
     * */
    public Map<String, String> getErrorMessage(HttpServletRequest request) {

        Map<String, String> map = new HashMap<String, String>();

        Map<String, Object> errorAttributes = getErrorAttributes(request, true);
        Integer status = (Integer) errorAttributes.get("status");
        String path = (String) errorAttributes.get("path");
        String message = (String) errorAttributes.get("message");
        map.put("status", status.toString());
        map.put("path", path);
        map.put("message", message);
        map.put("trace", errorAttributes.get("trace")+"");
        return map;
    }
}
